package com.maiji.cloud.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.maiji.cloud.config.MyRedisConfig;
import com.maiji.cloud.entities.login.*;
import com.maiji.cloud.entities.shopingmall.CapitalMain;
import com.maiji.cloud.entities.shopingmall.DistributionUserRuleLog;
import com.maiji.cloud.mapper.AppUserMapper;
import com.maiji.cloud.mapper.LogOutMapper;
import com.maiji.cloud.microservice.CapitalMainMService;
import com.maiji.cloud.request.BaseDataReqDto;
import com.maiji.cloud.request.ReqMetaData;
import com.maiji.cloud.response.*;
import com.maiji.cloud.response.login.AppUserResData;
import com.maiji.cloud.response.login.UserInfoResData;
import com.maiji.cloud.service.AppUserService;
import com.maiji.cloud.service.UserService;
import com.maiji.cloud.utils.BaseService;
import com.maiji.cloud.utils.RedisUtil;
import com.maiji.cloud.utils.UUID_MD5;
import org.apache.commons.lang.BooleanUtils;
import org.eclipse.jetty.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Transactional
public class AppUserServiceImpl extends ServiceImpl<AppUserMapper, AppUser> implements AppUserService {

	private static final Logger logger = LoggerFactory.getLogger(AppUserServiceImpl.class);
    @Autowired
    private AppUserService appUserService;
    @Autowired
    private RedisTemplate<String, Object> maiji1RedisTemplate;
    @Autowired
    private RedisTemplate<String, Object> maiji2RedisTemplate;
	@Autowired
	private UserService userService;
	@Autowired
	private CapitalMainMService capitalMainMService;
	@Autowired
	private AppUserMapper appUserMapper;
	@Autowired
	private LogOutMapper logOutMapper;
	@Autowired
	private MongoTemplate mongoTemplate;

    @Override
    public BaseResDto checkLogon(String tel) {
        AppUser appUser = selectOne(new EntityWrapper<AppUser>().eq("tel", tel));
        if (appUser != null) return new BaseResDto(Status.REGISTERED);
        return new BaseResDto(Status.UNREGISTERED);
    }

	@Override
	public BaseDataResDto<String> logon(String tel, String code, String pwd, String distributionNum) {
		if (StringUtil.isBlank(tel) || !tel.matches("^[1][0-9]{10}$") || StringUtil.isBlank(code)
				|| StringUtil.isBlank(pwd) || !pwd.matches("^(?=.*[a-zA-Z])(?=.*\\d)[a-zA-Z\\d]{6,}$"))
			return new BaseDataResDto(Status.PARAMETERERROR);
		// 检查验证码是否有效
		if (! checkCode(tel, code)) return new BaseDataResDto(Status.IDENTIFYCODEINVALID);
		// 验证该手机号是否已注册
		if (selectOne(new EntityWrapper<AppUser>().eq("tel", tel)) != null)
			return new BaseDataResDto(Status.REGISTERED);
		// 注册新用户
		String token = UUID_MD5.md5Str(tel + pwd.toUpperCase() + System.currentTimeMillis());
		AppUser appUser = new AppUser().setUuId(UUID_MD5.getUUID()).setTel(tel).setIsBan(0)
                .setPwd(UUID_MD5.md5Str(pwd)).setToken(token).setTokenStatus(1).setRegDate(new Date());
        if(StringUtil.isNotBlank(distributionNum)) {
            String pidUserId = checkDistributionNum(distributionNum);
            if(StringUtil.isNotBlank(pidUserId) ) {
                DistributionRuleConfigEntity distributionRuleConfig = mongoTemplate.findOne(new Query(),
                        DistributionRuleConfigEntity.class, DistributionRuleConfigEntity.TABLE_NAME);
                Date endTime = null;
                if (distributionRuleConfig != null) {
                    Integer num = distributionRuleConfig.getNum();
                    Integer unit = distributionRuleConfig.getUnit();
                    if (num != null && unit != null) {
                        Calendar calendar = Calendar.getInstance();
                        calendar.setTime(new Date());
                        switch (unit) {
                            case 1:
                                calendar.add(calendar.YEAR, num);// 增加几年,负数为减少几年
                                break;
                            case 2:
                                calendar.add(calendar.MONTH, num);// 增加几月,负数为减少几月
                                break;
                            case 3:
                                calendar.add(calendar.DATE, num);// 增加几天,负数为减少几天
                                break;
                        }
                        endTime = calendar.getTime();
                    }
                }
                appUser.setPid(pidUserId).setEndTime(endTime);
                logonPidCount(appUser);
            }
        }
        if (! insert(appUser)) return new BaseDataResDto<>(Status.APPUSERINSERTFAILED);
        if (! capitalMainMService.createCapitalMain(appUser.getUuId()))
            return new BaseDataResDto<>(Status.ERROR.setMessage("创建用户资金账户失败"));
		UserInfo userInfo = new UserInfo().setUuId(UUID_MD5.getUUID()).setUserId(appUser.getUuId()).setRegDate(new Date());
		while (true) {
			String rNickName = UUID_MD5.randomNickName();
			if (userService.selectOne(new EntityWrapper<UserInfo>().eq("nick_name", rNickName)) == null) {
				userInfo.setNickName(rNickName);
				break;
			}
		}
		if (! userService.insert(userInfo)) return new BaseDataResDto<>(Status.ERROR.setMessage("创建用户基本信息失败"));
		RedisUtil.setObject(maiji1RedisTemplate, "maijiToken:" + token, appUser);
		if (maiji2RedisTemplate != null) RedisUtil.setObject(maiji2RedisTemplate, "maijiToken:" + token, appUser);
		return new BaseDataResDto<String>(Status.SUCCESS).setData(token);
	}

	@Override
	public void logonPidCount(AppUser appUser) {
	    if (StringUtil.isBlank(appUser.getPid())) return;
	    List<AppUser> appUserList = Lists.newArrayList();
        AppUser pidAppUser = selectById(appUser.getPid());
        pidAppUser.setPidCount(pidAppUser.getPidCount() + 1);
        appUserList.add(pidAppUser);
        if (StringUtil.isNotBlank(pidAppUser.getPid())) {
            AppUser ppidAppUser = selectById(pidAppUser.getPid());
            ppidAppUser.setPpidCount(ppidAppUser.getPpidCount() + 1);
            appUserList.add(ppidAppUser);
        }
        updateBatchById(appUserList);
    }

	@Override
	public void logoffPidCount(AppUser appUser) {
        UserInfo userInfo = new UserInfo().setIdCard("123456");
        Wrapper<UserInfo> wrapper = new EntityWrapper<UserInfo>()
                .eq("user_id", appUser.getUuId());
        userService.update(userInfo, wrapper);
	    if (StringUtil.isBlank(appUser.getPid())) return;
	    List<AppUser> appUserList = Lists.newArrayList();
        AppUser pidAppUser = selectById(appUser.getPid());
        pidAppUser.setPidCount(pidAppUser.getPidCount() - 1);
        pidAppUser.setPpidCount(pidAppUser.getPpidCount() - appUser.getPidCount());
        appUserList.add(pidAppUser);
        if (StringUtil.isNotBlank(pidAppUser.getPid())) {
            AppUser ppidAppUser = selectById(pidAppUser.getPid());
            ppidAppUser.setPpidCount(ppidAppUser.getPpidCount() - 1);
            appUserList.add(ppidAppUser);
        }
        updateBatchById(appUserList);
    }

	@Override
	public BaseDataResDto<String> login(String tel, String pwd, String code, String openId, String qqId, String wbId, String distributionNum) {
		// 验证手机号是否注册或第三方账号是否绑定已注册的账号
		EntityWrapper<AppUser> entityWrapper = new EntityWrapper<>();
		Boolean flag = false;
		if (StringUtil.isNotBlank(tel)) {
			entityWrapper.eq("tel", tel);
			flag = true;
		}
		if (StringUtil.isNotBlank(openId)) {
			entityWrapper.eq("open_id", openId);
			flag = true;
		}
		if (StringUtil.isNotBlank(qqId)) {
			entityWrapper.eq("qq_id", qqId);
			flag = true;
		}
		if (StringUtil.isNotBlank(wbId)) {
			entityWrapper.eq("wb_id", wbId);
			flag = true;
		}
		if (! flag) return new BaseDataResDto<>(Status.PARAMETERERROR);
		AppUser appUser = selectOne(entityWrapper);// 手机验证码登录
        if (StringUtil.isNotBlank(tel) && StringUtil.isNotBlank(code))
            if (! checkCode(tel, code)) return new BaseDataResDto(Status.IDENTIFYCODEINVALID);
		if (appUser == null) {
            if (StringUtil.isNotBlank(tel) && StringUtil.isNotBlank(code)) return logon(tel, code, "123abc", distributionNum);
		    return new BaseDataResDto<>(Status.UNREGISTERED);
        }
		if (appUser.getIsBan() == 1) return new BaseDataResDto<>(Status.USER_WORNING_INFO.setMessage("该账户已被禁止登录"));
		// 账号密码登录
		if (StringUtil.isNotBlank(tel) && StringUtil.isNotBlank(pwd))
			if (! pwd.matches("^(?=.*[a-zA-Z])(?=.*\\d)[a-zA-Z\\d]{6,}$")
                    || ! appUser.getPwd().equals(UUID_MD5.md5Str(pwd)))
				return new BaseDataResDto(Status.LOGINFAILED);
        maiji1RedisTemplate.delete("maijiToken:" + appUser.getToken());
        if (maiji2RedisTemplate != null) maiji2RedisTemplate.delete("maijiToken:" + appUser.getToken());
		// 返回新登录状态的token
		String token = UUID_MD5.md5Str(tel + appUser.getPwd().toUpperCase() + System.currentTimeMillis());
		if (! updateById(appUser.setToken(token).setTokenStatus(1)))
			new BaseDataResDto(Status.TOKENREFRESHFAILED);
        RedisUtil.setObject(maiji1RedisTemplate, "maijiToken:" + token, appUser);
        if (maiji2RedisTemplate != null) RedisUtil.setObject(maiji2RedisTemplate, "maijiToken:" + token, appUser);
		return new BaseDataResDto<String>(Status.SUCCESS).setData(token);
	}

	@Override
	public BaseResDto logout(String token) {
		AppUser appUser = RedisUtil.getAppUserByRedis(maiji1RedisTemplate, MyRedisConfig.REDISDATABASENO, token, appUserService);
		if (appUser == null) return new BaseResDto(Status.TOKENINVALID);
        if (token.equals(appUser.getToken())) appUser.setTokenStatus(0);
		if (token.equals(appUser.getTokenWx())) appUser.setTokenStatusWx(0);
		if (! updateById(appUser)) return new BaseResDto(Status.ERROR.setMessage("修改token状态失败"));
        maiji1RedisTemplate.delete("maijiToken:" + token);
        if (maiji2RedisTemplate != null) maiji2RedisTemplate.delete("maijiToken:" + token);
		return new BaseResDto(Status.SUCCESS);
	}

	@Override
	public BaseDataResDto<AppUserResData> bindTel(String tel, String code, String openId, String qqId, String wbId,
			String nickName, String headUrl, String distributionNum) {
        // 验证验证码是否一致并有效
        if (! checkCode(tel, code)) return new BaseDataResDto(Status.IDENTIFYCODEINVALID);
		// 验证手机号是否已注册
		AppUser appUser = selectOne(new EntityWrapper<AppUser>().eq("tel", tel));
		// 未注册
		String pwd = null;
		if (appUser == null) { // 未注册
			pwd = UUID_MD5.randomPwd();
			String token = UUID_MD5.md5Str(tel + pwd.toUpperCase() + System.currentTimeMillis());
			appUser = new AppUser().setUuId(UUID_MD5.getUUID()).setPwd(UUID_MD5.md5Str(pwd))
                    .setTel(tel).setToken(token).setTokenStatus(1).setRegDate(new Date()).setIsBan(0);
            if(StringUtil.isNotBlank(distributionNum)) {
                String pidUserId = checkDistributionNum(distributionNum);
                if(StringUtil.isNotBlank(pidUserId)) {
                    appUser.setPid(pidUserId);
                    logonPidCount(appUser);
                }
            }
			if (! insert(appUser.setOpenId(openId).setQqId(qqId).setWbId(wbId)))
			    return new BaseDataResDto<>(Status.APPUSERINSERTFAILED);
            if (! capitalMainMService.createCapitalMain(appUser.getUuId()))
                return new BaseDataResDto<>(Status.ERROR.setMessage("创建用户资金账户失败"));
		} else {
            if (appUser.getIsBan() == 1) return new BaseDataResDto<>(Status.USER_WORNING_INFO.setMessage("该账户已被禁止登录"));
		    if (! updateById(appUser.setOpenId(openId).setQqId(qqId).setWbId(wbId))) // 已注册
                return new BaseDataResDto<>(Status.APPUSERINSERTFAILED);
        }
		// 保存用户头像
		UserInfo userInfo = userService.selectOne(new EntityWrapper<UserInfo>().eq("user_id", appUser.getUuId()));
		if (userInfo == null) { // 未注册
			userInfo = new UserInfo().setUuId(UUID_MD5.getUUID()).setUserId(appUser.getUuId())
					.setNickName(nickName).setHeadUrl(headUrl).setRegDate(new Date());
			if (! userService.insert(userInfo)) return new BaseDataResDto<>(Status.ERROR.setMessage("保存用户基本信息失败！"));
		} else { // 已注册
			if (StringUtil.isBlank(userInfo.getNickName()) || userInfo.getNickName().startsWith("麦吉-")) userInfo.setNickName(nickName);
			if (StringUtil.isBlank(userInfo.getHeadUrl())) userInfo.setHeadUrl(headUrl);
			if (! userService.updateById(userInfo)) return new BaseDataResDto<>(Status.ERROR.setMessage("保存用户基本信息失败！"));
		}
		RedisUtil.setObject(maiji1RedisTemplate, "maijiToken:" + appUser.getToken(), appUser);
        if (maiji2RedisTemplate != null) RedisUtil.setObject(maiji2RedisTemplate, "maijiToken:" + appUser.getToken(), appUser);
		AppUserResData appUserResData = new AppUserResData().setToken(appUser.getToken());
		if (StringUtil.isNotBlank(pwd)) appUserResData.setPwd(pwd);
		return new BaseDataResDto<AppUserResData>(Status.SUCCESS).setData(appUserResData);
	}

	@Override
	public BaseDataResDto<String> updatePwd(String maijiToken, String tel, String code, String oldPwd, String pwd) {
        AppUser appUser = null;
        if (StringUtil.isNotBlank(tel)) {
            // 验证验证码是否一致并有效
            if (StringUtil.isNotBlank(code) && ! checkCode(tel, code))
                return new BaseDataResDto(Status.IDENTIFYCODEINVALID);
            // 验证手机号是否已注册
            appUser = selectOne(new EntityWrapper<AppUser>().eq("tel", tel));
        }
		if (StringUtil.isNotBlank(maijiToken))
		    appUser = RedisUtil.getAppUserByRedis(maiji1RedisTemplate, MyRedisConfig.REDISDATABASENO, maijiToken, appUserService);
		if (appUser == null) return new BaseDataResDto(Status.UNREGISTERED);
		if (StringUtil.isNotBlank(oldPwd))
		    if (! UUID_MD5.md5Str(oldPwd).equals(appUser.getPwd()))
		        return new BaseDataResDto(Status.PWDOLDERROR.setMessage("原密码错误"));
        if (UUID_MD5.md5Str(pwd).equals(appUser.getPwd()))
            return new BaseDataResDto(Status.UPDATEPWDERROR);
		String token = UUID_MD5.md5Str(tel + pwd.toUpperCase() + System.currentTimeMillis());
		appUser.setPwd(UUID_MD5.md5Str(pwd)).setToken(token).setTokenStatus(1);
		if (!updateById(appUser)) return new BaseDataResDto<>(Status.APPUSERINSERTFAILED);
		maiji1RedisTemplate.delete("maijiToken:" + maijiToken);
		RedisUtil.setObject(maiji1RedisTemplate, "maijiToken:" + token, appUser);
        if (maiji2RedisTemplate != null) {
            maiji2RedisTemplate.delete("maijiToken:" + maijiToken);
            RedisUtil.setObject(maiji2RedisTemplate, "maijiToken:" + token, appUser);
        }
		return new BaseDataResDto<String>(Status.SUCCESS).setData(token);
	}

	@Override
	public BaseDataResDto<String> updateTel(String tel, String code, String token) {
	    // 验证该手机号是否已注册
        AppUser appUser = selectOne(new EntityWrapper<AppUser>().eq("tel", tel));
        if (appUser != null) return new BaseDataResDto<>(Status.ERROR.setMessage("手机号已注册"));
        // 验证验证码是否一致并有效
		if (!checkCode(tel, code)) return new BaseDataResDto(Status.IDENTIFYCODEINVALID);
		appUser = RedisUtil.getAppUserByRedis(maiji1RedisTemplate, MyRedisConfig.REDISDATABASENO, token, appUserService);
		// 修改手机号后返回新登录状态的token
		String tokenNew = UUID_MD5.md5Str(tel + appUser.getPwd().toUpperCase() + System.currentTimeMillis());
		appUser.setTel(tel).setToken(tokenNew).setTokenStatus(1);
		if (! updateById(appUser)) return new BaseDataResDto<>(Status.APPUSERINSERTFAILED);
		RedisUtil.setObject(maiji1RedisTemplate, "maijiToken:" + tokenNew, appUser);
        if (maiji2RedisTemplate != null) RedisUtil.setObject(maiji2RedisTemplate, "maijiToken:" + tokenNew, appUser);
		return new BaseDataResDto<String>(Status.SUCCESS).setData(tokenNew);
	}

	@Override
	public AppUser checkToken(String maijiToken) {
	    return checkToken(maijiToken, false);
    }

	@Override
	public void deleteAppUserByRedis(String maijiToken) {
        if (maiji1RedisTemplate != null) maiji1RedisTemplate.delete("maijiToken:"+maijiToken);
        if (maiji2RedisTemplate != null) maiji2RedisTemplate.delete("maijiToken:"+maijiToken);
	}

    @Override
	public AppUser checkToken(String maijiToken, Boolean isOfficial) {
        AppUser appUser1 =  (AppUser) maiji1RedisTemplate.opsForValue().get("maijiToken:"+maijiToken);
        AppUser appUser2 = null;
        if (maiji2RedisTemplate != null) appUser2 = (AppUser) maiji2RedisTemplate.opsForValue().get("maijiToken:"+maijiToken);
		if (appUser1 == null || maiji2RedisTemplate != null && appUser2 == null) {
			EntityWrapper<AppUser> entityWrapper = new EntityWrapper<>();
			entityWrapper.eq("token", maijiToken);
			entityWrapper.eq("token_status", 1);
			entityWrapper.or();
			entityWrapper.eq("token_wx", maijiToken);
			entityWrapper.eq("token_status_wx", 1);
			entityWrapper.or();
			entityWrapper.eq("token_bd", maijiToken);
			entityWrapper.eq("token_status_bd", 1);
			if (BooleanUtils.isTrue(isOfficial)) {
                entityWrapper.or();
                entityWrapper.eq("token", maijiToken);
            }
            appUser1 = selectOne(entityWrapper);
			if (appUser1 != null){
                RedisUtil.setObject(maiji1RedisTemplate, "maijiToken:" + maijiToken, appUser1);
                if (maiji2RedisTemplate != null) RedisUtil.setObject(maiji2RedisTemplate, "maijiToken:" + maijiToken, appUser1);
            }
		}
        if (appUser1 != null && appUser1.getIsBan() == 1) return null;
		return appUser1;
	}

	@Override
	public Boolean checkCode(String tel, String code) {
		String encryptionCode = (String) maiji1RedisTemplate.opsForValue().get("code:" + tel);
		if (encryptionCode == null)
			return false;
		return UUID_MD5.md5Str(code).equals(encryptionCode);
	}

	/**
	 * 根据分校码查看用户id并校验分校码是否正确
	 * @param distributionNum
	 * @return
	 */
	public String checkDistributionNum(String distributionNum) {
		if (StringUtil.isBlank(distributionNum)) return null;
		AppUser appUser = selectOne(new EntityWrapper<AppUser>()
                .eq("distribution_num", distributionNum).ne("is_cancel", 1));
		if(appUser != null) return appUser.getUuId();
		return null;
	}

	@Override
	public BaseResDto logoutAccount(BaseDataReqDto<String> param, String maijiToken) {
		logger.info("AppUserServiceImpl.logoutAccount ,maijiToken is {}",  maijiToken);
		AppUser appUser = appUserService.checkToken(maijiToken);
		if (appUser == null) {
			logger.info("AppUserServiceImpl.logoutAccount ,appUser is {}", JSON.toJSONString(appUser));
			return new BaseResDto(Status.ERROR, "token无效");
		}
		LogOutEntity logOutEntity = new LogOutEntity();
		BeanUtils.copyProperties(appUser, logOutEntity);
		logOutEntity.setUuId(UUID_MD5.getUUID());
		logOutEntity.setUserId(appUser.getUuId());
		logOutEntity.setLogoutTime(new Date());
		logOutEntity.setReason(param.getData());
		//注销记录
		logOutMapper.insert(logOutEntity);
		
		appUser.setDistributionNum(null);
		appUser.setTel(null);
		appUser.setQqId(null);
		appUser.setWbId(null);
		appUser.setOpenId(null);
		appUser.setOpenIdWx(null);
		appUser.setTokenStatus(0);
		appUser.setTokenStatusWx(0);
		//删除注册信息
		appUserMapper.updateByUuId(appUser);
		//解除层级关系
		appUserMapper.updateByPid(appUser.getUuId());

		logoffPidCount(appUser);

		return new BaseResDto(Status.SUCCESS);
	}

	@Override
    public BaseMetaResDto<List<AppUserResData>> findAllDistributionUsers(String pid, String nickName, String tel, ReqMetaData metaData) {
        EntityWrapper<AppUser> entityWrapper = new EntityWrapper<>();
        entityWrapper.isNotNull("tel");
        entityWrapper.orderBy("pid_count", false);
        Boolean flag = true;
        if (StringUtil.isBlank(nickName) && StringUtil.isBlank(tel) && StringUtil.isBlank(pid)) {
            flag = false;
            entityWrapper.isNull("pid");
            entityWrapper.isNotNull("distribution_num");
        }
        if (StringUtil.isNotBlank(pid)) {
            flag = false;
            entityWrapper.eq("pid", pid);
        }
        if (flag && StringUtil.isNotBlank(nickName)) {
            List<UserInfo> userInfos = userService.selectList(new EntityWrapper<UserInfo>().like("nick_name", nickName));
            List<String> userIds = userInfos.parallelStream().map(UserInfo::getUserId).collect(Collectors.toList());
            if (userIds.size() > 0) {
                entityWrapper.in("uu_id", userIds);
                entityWrapper.andNew();
                entityWrapper.isNotNull("pid");
                entityWrapper.or();
                entityWrapper.isNotNull("distribution_num");
            }
        }
        if (flag && StringUtil.isNotBlank(tel)) entityWrapper.like("tel", tel);
        Page<AppUser> page = selectPage(new Page<>(metaData.getPage(), metaData.getSize()), entityWrapper);
        List<String> userIds = page.getRecords().parallelStream().map(AppUser::getUuId).collect(Collectors.toList());
        List<UserInfo> userInfos = userService.selectList(new EntityWrapper<UserInfo>().in("user_id", userIds));
        List<AppUserResData> appUserResDataList = BaseService.dealWithOneToOne(page.getRecords(), "getUuId",
                AppUserResData.class, "setUserInfo", userInfos, "getUserId", UserInfoResData.class);
        appUserResDataList = BaseService.dealWithOneToOne(appUserResDataList,"getUuId", AppUserResData.class,
                "setCapitalMain", capitalMainMService.findAllCapitalMains(userIds),"getUserId", CapitalMain.class);
        ResMetaData resMetaData = new ResMetaData(page.getCurrent(), page.getSize(), page.getTotal());
        return new BaseMetaResDto<List<AppUserResData>>(Status.SUCCESS).setData(appUserResDataList).setResMetaData(resMetaData);
    }

    @Override
    public BaseResDto editDistributionUser(AppUser appUser) {
	    if (StringUtil.isBlank(appUser.getUuId())) return new BaseResDto(Status.ERROR);
	    if (! updateById(appUser)) return new BaseResDto(Status.ERROR);
        HashMap<Object, Object> logMap = Maps.newHashMap();
        logMap.put("endTime", appUser.getEndTime());
        logMap.put("isCancel", appUser.getIsCancel());
        logMap.put("ratio", appUser.getRatio());
        logMap.put("userId", appUser.getUuId());
        logMap.put("type", 1);
        logMap.put("editDate", new Date());
        logMap.put("operatorId", appUser.getOperatorId());
        logMap.put("operatorName", appUser.getOperatorName());
        mongoTemplate.save(logMap, "distribution_rule_log");
	    return new BaseResDto(Status.SUCCESS);
    }

    @Override
    public BaseDataResDto<List<DistributionUserRuleLog>> findAllDistributionUserRuleLogs(String userId, String nickName, List<Date> editDates) {
        Query query = new Query(Criteria.where("type").is(1))
                .with(new Sort(new Sort.Order(Sort.Direction.DESC,"editDate")));
        if (StringUtil.isNotBlank(userId)) query.addCriteria(Criteria.where("userId").is(userId));
        if (editDates != null) {
            Date startDate = editDates.size() > 0 ? editDates.get(0): null;
            Criteria updateDateCriteria = Criteria.where("editDate");
            Boolean updFlag = false;
            if (startDate != null) {
                updateDateCriteria = updateDateCriteria.gte(startDate);
                updFlag = true;
            }
            Date endDate = editDates.size() > 1 ? editDates.get(1): null;
            if (endDate != null) {
                updateDateCriteria = updateDateCriteria.lte(endDate);
                updFlag = true;
            }
            if (updFlag) query.addCriteria(updateDateCriteria);
        }
        List<UserInfo> userInfos = Lists.newArrayList();
        if (StringUtil.isNotBlank(nickName)) {
            userInfos = userService.selectList(new EntityWrapper<UserInfo>().like("nick_name", nickName));
            List<String> userIds = userInfos.parallelStream().map(UserInfo::getUserId).collect(Collectors.toList());
            query.addCriteria(Criteria.where("uuId").in(userIds));
        }
        List<DistributionUserRuleLog> ruleLogList = mongoTemplate.find(query, DistributionUserRuleLog.class, DistributionUserRuleLog.TABLE_NAME);
        if (userInfos.size() == 0) {
            List<String> userIds = ruleLogList.parallelStream().map(DistributionUserRuleLog::getUserId).collect(Collectors.toList());
            userInfos = userService.selectList(new EntityWrapper<UserInfo>().in("user_id", userIds));
        }
        ruleLogList = BaseService.dealWithOneToOne(ruleLogList, "getUuId", DistributionUserRuleLog.class,
                "setUserInfo", userInfos, "getUserId", UserInfo.class);
        return new BaseDataResDto<List<DistributionUserRuleLog>>(Status.SUCCESS).setData(ruleLogList);
    }

    @Override
    public BaseDataResDto<HashMap<String, Integer>> findDistributionUserCount () {
        HashMap<String, Integer> map = Maps.newHashMap();
        EntityWrapper<AppUser> entityWrapper = new EntityWrapper<>();
        entityWrapper.isNotNull("pid");
        entityWrapper.or();
        entityWrapper.isNotNull("distribution_num");
        int sum = selectCount(entityWrapper);
        map.put("sum", sum);
        EntityWrapper<AppUser> entityWrapper1 = new EntityWrapper<>();
        entityWrapper1.isNotNull("pid");
        entityWrapper1.isNull("distribution_num");
        int leaf = selectCount(entityWrapper1);
        map.put("leaf", leaf);
        map.put("branch", sum - leaf);
        return new BaseDataResDto<HashMap<String, Integer>>(Status.SUCCESS).setData(map);
    }

    @Override
    public BaseResDto banAppUser(AppUser appUser) {
	    AppUser appUser123 = selectById(appUser.getUuId())
                .setTokenStatus(0).setTokenStatusWx(0).setIsBan(appUser.getIsBan());
        if (! updateById(appUser123)) return new BaseResDto(Status.ERROR);
        List<String> maijiTokenKeys = Arrays.asList("maijiToken:" +
                appUser123.getToken(), "maijiToken:" + appUser123.getTokenWx());
        maiji1RedisTemplate.delete(maijiTokenKeys);
        if (maiji2RedisTemplate != null) maiji2RedisTemplate.delete(maijiTokenKeys);
        return new BaseResDto(Status.SUCCESS);
    }

}
